<template>
	<view class="upload-page">
		<scroll-view scroll-y class="scroll-area">
			<view class="section card">
				<view class="section-header">
					<text class="section-title">视频素材</text>
					<text class="section-subtitle">选择已拍摄的视频文件</text>
				</view>

				<view v-if="!videoInfo" class="picker-placeholder">
					<view class="placeholder-text">暂未选择视频</view>
					<button class="primary-btn" size="mini" @click="handleChooseVideo">
						选择视频
					</button>
				</view>

				<view v-else class="preview-wrapper">
					<video
						class="video-preview"
						:src="previewSrc"
						:poster="videoInfo.thumbTempFilePath || ''"
						controls
						:muted="true"
						:show-fullscreen-btn="true"
						:show-play-btn="true"
						:show-center-play-btn="true"
						object-fit="cover"
					></video>

					<view class="video-meta">
						<view class="meta-row">
							<text class="meta-label">时长</text>
							<text class="meta-value">{{ (videoInfo.duration || 0).toFixed(1) }}s</text>
						</view>
						<view class="meta-row">
							<text class="meta-label">尺寸</text>
							<text class="meta-value">{{ videoInfo.width }} × {{ videoInfo.height }}</text>
						</view>
						<view class="meta-row">
							<text class="meta-label">大小</text>
							<text class="meta-value">{{ readableSize }}</text>
						</view>
					</view>

					<view class="upload-progress" v-if="isUploading">
						<text>上传中 {{ uploadProgress }}%</text>
					</view>

					<view class="preview-actions">
						<button class="ghost-btn" size="mini" :disabled="isUploading || isPublishing" @click="handleChooseVideo">
							重新选择
						</button>
						<button class="primary-btn" size="mini" :loading="isUploading" :disabled="videoInfo.uploaded || isUploading" @click="handleUpload">
							{{ isUploading ? '上传中' : (videoInfo.uploaded ? '已上传' : '重新上传') }}
						</button>
					</view>
				</view>
			</view>

			<view class="section card">
				<view class="section-header">
					<text class="section-title">标题</text>
				</view>
				<uni-easyinput
					class="dark-easyinput"
					v-model="form.title"
					placeholder="给视频起个吸引人的标题"
					placeholder-style="color: rgba(255,255,255,0.5)"
					:maxlength="40"
					:input-border="false"
					:styles="titleInputStyles"
				/>
			</view>

			<view class="section card">
				<view class="section-header">
					<text class="section-title">描述</text>
					<text class="section-subtitle">可选，描述视频亮点</text>
				</view>
				<view class="description-preview">
					<text class="preview-label">效果预览</text>
					<view class="preview-content">
						<template v-if="descriptionSegments.length">
							<text
								v-for="(segment, idx) in descriptionSegments"
								:key="idx"
								:class="['preview-fragment', { 'tag-text': segment.isTag }]"
							>
								{{ segment.text }}
							</text>
						</template>
						<text v-else class="preview-placeholder">
							输入描述内容或点击下方推荐标签自动插入
						</text>
					</view>
				</view>
				<textarea
					class="description"
					v-model="form.description"
					placeholder="介绍一下视频的背景、要点或想说的话"
					:maxlength="200"
					:auto-height="true"
				/>
				<view class="tag-helper">
					<text class="tag-helper-title">推荐标签</text>
					<view class="tag-list">
						<view
							v-for="tag in recommendedTags"
							:key="tag"
							:class="['tag-chip', { active: isTagSelected(tag) }]"
							@click="toggleTag(tag)"
						>
							#{{ tag }}
						</view>
					</view>
				</view>
			</view>
		</scroll-view>

		<view class="publish-bar">
			<view class="tips">
				<text>视频上传完成后即可发布</text>
			</view>
			<button
				:class="['publish-btn', { disabled: !canPublish }]"
				type="primary"
				:loading="isPublishing"
				:disabled="isPublishing"
				@click="handlePublish"
			>
				发布视频
			</button>
		</view>
	</view>
</template>

<script setup>
import { ref, computed, onUnmounted } from 'vue'
import { uploadVideo } from '@/api/file.js'

const videoInfo = ref(null)
const form = ref({
	title: '',
	description: ''
})

const titleInputStyles = {
	backgroundColor: 'rgba(255, 255, 255, 0.06)',
	color: '#fff',
	borderColor: 'rgba(255, 255, 255, 0.12)',
	borderRadius: '16rpx',
	paddingLeft: '24rpx',
	paddingRight: '24rpx',
	minHeight: '88rpx'
}

const recommendedTags = ['美食', '旅游', '科技', '教育', '健康', '财经']
const uploadTask = ref(null)
const uploadProgress = ref(0)

const isUploading = ref(false)
const isPublishing = ref(false)

const readableSize = computed(() => {
	if (!videoInfo.value?.size) return '--'
	const size = videoInfo.value.size
	if (size < 1024) return `${size}B`
	if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)}KB`
	return `${(size / (1024 * 1024)).toFixed(1)}MB`
})

const previewSrc = computed(() => {
	if (videoInfo.value?.remoteUrl) return videoInfo.value.remoteUrl
	return videoInfo.value?.tempFilePath || ''
})

const hasUploadedVideo = computed(() => Boolean(videoInfo.value && videoInfo.value.uploaded))
const hasTitle = computed(() => form.value.title.trim().length > 0)
const hasDescription = computed(() => form.value.description.trim().length > 0)

const canPublish = computed(() => {
	return hasUploadedVideo.value && hasTitle.value && hasDescription.value && !isUploading.value
})

const resetForm = () => {
	form.value = {
		title: '',
		description: ''
	}
}

const hashtagRegex = /#([\u4e00-\u9fa5A-Za-z0-9_]+)/g

const descriptionSegments = computed(() => {
	const text = form.value.description || ''
	const segments = []
	if (!text) return segments
	let lastIndex = 0
	let match

	while ((match = hashtagRegex.exec(text)) !== null) {
		if (match.index > lastIndex) {
			segments.push({
				text: text.slice(lastIndex, match.index),
				isTag: false
			})
		}
		segments.push({ text: match[0], isTag: true })
		lastIndex = hashtagRegex.lastIndex
	}

	if (lastIndex < text.length) {
		segments.push({
			text: text.slice(lastIndex),
			isTag: false
		})
	}

	// 重置 lastIndex，避免下一次计算受到影响
	hashtagRegex.lastIndex = 0
	return segments
})

const currentTags = computed(() => {
	const text = form.value.description || ''
	const tags = new Set()
	let match
	while ((match = hashtagRegex.exec(text)) !== null) {
		if (match[1]) tags.add(match[1])
	}
	hashtagRegex.lastIndex = 0
	return Array.from(tags)
})

const isTagSelected = (tag) => currentTags.value.includes(tag)

const toggleTag = (tag) => {
	const token = `#${tag}`
	const desc = form.value.description || ''

	if (isTagSelected(tag)) {
		const regex = new RegExp(`(^|[\\s])${token}(?=[\\s]|$)`, 'g')
		form.value.description = desc
			.replace(regex, (_, prefix) => prefix || '')
			.replace(/[ \t]{2,}/g, ' ')
			.trim()
		return
	}

	const base = desc.trim()
	form.value.description = base ? `${base} ${token} ` : `${token} `
}

const handleChooseVideo = () => {
	if (isUploading.value || isPublishing.value) return

	uni.chooseVideo({
		sourceType: ['album', 'camera'],
		compressed: true,
		success: (res) => {
			videoInfo.value = {
				tempFilePath: res.tempFilePath,
				thumbTempFilePath: res.thumbTempFilePath,
				duration: res.duration,
				size: res.size,
				height: res.height,
				width: res.width,
				fileType: res.fileType,
				uploaded: false,
				remoteUrl: ''
			}
			uploadProgress.value = 0
			resetForm()
			handleUpload()
		},
		fail: (err) => {
			// 用户取消不提示
			if (err?.errMsg && err.errMsg.includes('cancel')) return
			uni.showToast({
				title: '选择失败，请重试',
				icon: 'none'
			})
		}
	})
}

const mockRequest = (ms = 1200) => {
	return new Promise((resolve) => {
		setTimeout(resolve, ms)
	})
}

const handleUpload = async () => {
	if (!videoInfo.value || isUploading.value) return

	isUploading.value = true
	videoInfo.value.uploaded = false
	videoInfo.value.remoteUrl = ''
	uploadProgress.value = 0
	uni.showLoading({ title: '上传中...', mask: true })

	try {
		const resp = await uploadVideo(videoInfo.value.tempFilePath, {
			hideToast: true,
			onTaskReady: (task) => {
				uploadTask.value = task
			},
			onProgress: ({ progress }) => {
				uploadProgress.value = progress
			}
		})

		const fileUrl = resp?.data?.url || resp?.data?.fileUrl || resp?.url
		console.log("视频地址",fileUrl);
		if (fileUrl) {
			videoInfo.value.remoteUrl = fileUrl
			videoInfo.value.uploaded = true
			uni.showToast({ title: '上传成功', icon: 'success' })
		} else {
			throw new Error('MISSING_FILE_URL')
		}
	} catch (error) {
		const message = error?.message === 'MISSING_FILE_URL' ? '上传响应缺少地址' : '上传失败，请重试'
		uni.showToast({ title: message, icon: 'none' })
	} finally {
		if (uploadTask.value) {
			uploadTask.value = null
		}
		isUploading.value = false
		uni.hideLoading()
	}
}
const handlePublish = async () => {
	if (isPublishing.value) return

	if (!canPublish.value) {
		const missing = []
		if (!hasUploadedVideo.value) missing.push('上传视频')
		if (!hasTitle.value) missing.push('输入标题')
		if (!hasDescription.value) missing.push('输入描述')

		uni.showToast({
			title: `请先完成：${missing.join('、')}`,
			icon: 'none'
		})
		return
	}

	isPublishing.value = true
	try {
		// TODO: 调用发布接口
		await mockRequest(1000)
		uni.showToast({ title: '发布成功', icon: 'success' })
		setTimeout(() => {
			uni.navigateBack({
				delta: 1,
				fail: () => {
					uni.reLaunch({ url: '/pages/index/index' })
				}
			})
		}, 800)
	} catch (err) {
		uni.showToast({ title: '发布失败，请重试', icon: 'none' })
	} finally {
		isPublishing.value = false
	}
}

onUnmounted(() => {
	if (uploadTask.value) {
		try {
			uploadTask.value.abort()
		} catch (e) {}
		uploadTask.value = null
	}
	uni.hideLoading()
})
</script>

<style scoped lang="scss">
.upload-page {
	min-height: 100vh;
	background: #0d0d0d;
	display: flex;
	flex-direction: column;
}

.scroll-area {
	flex: 1;
	padding: 24rpx;
	box-sizing: border-box;
}

.section {
	margin-bottom: 24rpx;
}

.card {
	background: rgba(255, 255, 255, 0.04);
	border: 2rpx solid rgba(255, 255, 255, 0.06);
	border-radius: 20rpx;
	padding: 32rpx;
	color: #fff;
}

.section-header {
	margin-bottom: 20rpx;
}

.section-title {
	font-size: 32rpx;
	font-weight: 600;
}

.section-subtitle {
	font-size: 24rpx;
	color: rgba(255, 255, 255, 0.6);
	margin-top: 8rpx;
	display: block;
}

.picker-placeholder {
	min-height: 240rpx;
	border: 2rpx dashed rgba(255, 255, 255, 0.2);
	border-radius: 16rpx;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 24rpx;
	color: rgba(255, 255, 255, 0.6);
}

.placeholder-text {
	font-size: 26rpx;
}

.preview-wrapper {
	display: flex;
	flex-direction: column;
	gap: 16rpx;
}

.video-preview {
	width: 100%;
	height: 400rpx;
	border-radius: 16rpx;
	background: #000;
}

.video-meta {
	display: flex;
	justify-content: space-between;
	gap: 12rpx;
	padding: 16rpx 20rpx;
	background: rgba(255, 255, 255, 0.06);
	border-radius: 12rpx;
	font-size: 24rpx;
}

.meta-row {
	display: flex;
	flex-direction: column;
	gap: 8rpx;
	min-width: 30%;
}

.meta-label {
	color: rgba(255, 255, 255, 0.6);
}

.meta-value {
	font-weight: 600;
}

.preview-actions {
	display: flex;
	justify-content: flex-end;
	gap: 16rpx;
}

.upload-progress {
	margin-top: 8rpx;
	font-size: 24rpx;
	color: rgba(255, 255, 255, 0.7);
}

.primary-btn,
.ghost-btn {
	padding: 0 24rpx;
	height: 64rpx;
	line-height: 64rpx;
	border-radius: 32rpx;
	color: #fff;
}

.primary-btn {
	background: linear-gradient(135deg, #7c3aed, #0ea5e9);
	border: none;
}

.ghost-btn {
	background: transparent;
	border: 2rpx solid rgba(255, 255, 255, 0.3);
}

.description {
	width: 100%;
	min-height: 160rpx;
	background: rgba(255, 255, 255, 0.06);
	border-radius: 16rpx;
	padding: 24rpx;
	color: #fff;
	font-size: 26rpx;
	box-sizing: border-box;
}

.dark-easyinput {
	:deep(.uni-easyinput__content) {
		background: rgba(255, 255, 255, 0.06);
		border-radius: 16rpx;
		border: 2rpx solid rgba(255, 255, 255, 0.08);
		padding: 0 24rpx;
		min-height: 88rpx;
		color: #fff;
	}

	:deep(.uni-easyinput__placeholder) {
		color: rgba(255, 255, 255, 0.5);
	}

	:deep(.is-textarea) {
		background: rgba(255, 255, 255, 0.06);
	}
}

.description-preview {
	margin-bottom: 24rpx;
	padding: 20rpx;
	border-radius: 16rpx;
	background: rgba(255, 255, 255, 0.03);
	border: 2rpx solid rgba(255, 255, 255, 0.06);
}

.preview-label {
	display: block;
	font-size: 24rpx;
	color: rgba(255, 255, 255, 0.6);
	margin-bottom: 12rpx;
}

.preview-content {
	font-size: 26rpx;
	color: rgba(255, 255, 255, 0.9);
	line-height: 1.6;
	white-space: pre-wrap;
}

.preview-fragment {
	color: inherit;
}

.tag-text {
	color: #ffb347;
	font-weight: 600;
}

.preview-placeholder {
	color: rgba(255, 255, 255, 0.4);
}

.tag-helper {
	margin-top: 24rpx;
}

.tag-helper-title {
	font-size: 24rpx;
	color: rgba(255, 255, 255, 0.6);
	margin-bottom: 16rpx;
	display: block;
}

.tag-list {
	display: flex;
	flex-wrap: wrap;
	gap: 16rpx;
}

.tag-chip {
	padding: 10rpx 24rpx;
	border-radius: 999rpx;
	font-size: 24rpx;
	color: rgba(255, 255, 255, 0.7);
	background: rgba(255, 255, 255, 0.08);
	border: 2rpx solid transparent;
}

.tag-chip.active {
	color: #111;
	background: linear-gradient(135deg, #f6d365, #fda085);
	border-color: rgba(255, 255, 255, 0.2);
	font-weight: 600;
}

.publish-bar {
	padding: 24rpx;
	padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
	background: rgba(13, 13, 13, 0.95);
	border-top: 2rpx solid rgba(255, 255, 255, 0.06);
}

.tips {
	font-size: 24rpx;
	color: rgba(255, 255, 255, 0.6);
	margin-bottom: 16rpx;
	text-align: center;
}

.publish-btn {
	width: 100%;
	height: 92rpx;
	background: linear-gradient(135deg, #ff512f, #dd2476);
	border-radius: 60rpx;
	color: #fff;
	font-size: 32rpx;
	border: none;
}

.publish-btn:disabled {
	background: rgba(255, 255, 255, 0.2);
	color: rgba(255, 255, 255, 0.6);
}

.publish-btn.disabled {
	background: rgba(255, 255, 255, 0.15);
	color: rgba(255, 255, 255, 0.5);
}
</style>

